using System;
using System.Collections.Generic;
using System.Text;
using PlainConcepts.Fx.Dnie.CertStore;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using PlainConcepts.Fx.Dnie.DigitalSign;
using PlainConcepts.Fx.Dnie.SmartCard.Interop;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

namespace PlainConcepts.Fx.Dnie
{
    /// <summary>
    /// Helper to manage Dni-e
    /// </summary>
	public class DnieHelper
	{
		#region Constructors

		/// <summary>
		/// Default Constructor
		/// </summary>
		public DnieHelper()
		{
		}

		#endregion

		#region Public Methods

		/// <summary>
		/// Get the identity of DNI
		/// </summary>
		/// <returns></returns>
		public DnieIdentity GetIdentity()
		{
			//Call CertStoreHelper and return Dnie Identity

            using (CertStoreHelper certStore = new CertStoreHelper())
            {
                return certStore.GetDnieIdentity();
            }
		}

		/// <summary>
		/// Sign document with dnie certificate
		/// </summary>
		/// <param name="pathDocument">Document to sign</param>
		/// <param name="outputPath">Path to the output document</param>
		public void SignDocument(string pathDocument, string outputPath)
		{

			//Asserts input values 
			Asserts.IsNullOrEmpty(pathDocument, "pathDocument");
			Asserts.IsNullOrEmpty(outputPath, "outputPath");
			Asserts.IsValidPath(pathDocument);

			string extension = Path.GetExtension(pathDocument);


            //Rethrow exception
            IDigitalSigner digitalSigner = SignerLoader.GetPlugin(extension); 
			
			//Call CertStoreHelper and return X509 Certificate

            using (CertStoreHelper certStore = new CertStoreHelper())
            {
                X509Certificate2 certToSign = certStore.GetCertificateToSign();
                digitalSigner.Sign(certToSign, pathDocument, outputPath);
            }
		}
        /// <summary>
        /// Validate if SmartCard is present
        /// </summary>
        /// <returns>True if smartcard is present, else false</returns>
		public bool IsSmartCardPresent()
		{
            try
            {
                MgScContext mgscContext = new MgScContext();
                GetSmartCard(ref mgscContext);
                return true;
            }
            catch (RuntimeWrappedException)
            {
                return false;
            }
            catch (Exception)
            {
                return false;
            }
		}

		#endregion

        #region Private Methods

        private SmartCardStatus GetSmartCard(ref MgScContext mgscContext)
        {
            mgscContext = new MgScContext();
            IntPtr pcscContext = (IntPtr)0;
            IntPtr cardHandle = (IntPtr)0;
            return (SmartCardStatus)GetSmartCard(ref mgscContext, ref pcscContext, ref cardHandle);
        }
        private Int32 GetSmartCard(
           [In, Out]       ref MgScContext mgscContext,
           [In, Out]       ref IntPtr pcscContext,
           [In, Out]       ref IntPtr cardHandle)
        {
            Int32 result = 0;
            PCSCOpenCardNameWEx ocnwex = new PCSCOpenCardNameWEx();
            bool cardIsLocked = false;
            string readerName;
            UInt32 readerNameLength = 0;
            UInt32 readerAndCardBufferLength = 256;
            UInt32 cardState = 0;
            UInt32 cardProtocol = 0;
            byte[] atr;
            UInt32 atrLength = 0;

            try
            {
                //
                // Get a context handle from the smart card resource manager
                //

                if (0 != (result = PersonalComputerSmartCard.SCardEstablishContext(
                        PCSCScope.SCARD_SCOPE_USER,
                        null,
                        null,
                        ref pcscContext)))
                    throw new Exception("SCardEstablishContext");

                //
                // Get a handle to a card, prompting the user if necessary
                //

                ocnwex.flags = PCSCDialogUI.SC_DLG_MINIMAL_UI;
                ocnwex.pcscContext = pcscContext;
                ocnwex.shareMode = PCSCShareMode.SCARD_SHARE_SHARED;
                ocnwex.preferredProtocols = PCSCProtocol.SCARD_PROTOCOL_Tx;
                ocnwex.reader = new string(
                    (char)0, (int)readerAndCardBufferLength);
                ocnwex.maxReaderLength = readerAndCardBufferLength;
                ocnwex.card = new string(
                    (char)0, (int)readerAndCardBufferLength);
                ocnwex.maxCardLength = readerAndCardBufferLength;

                if (0 != (result = MgSc.MgScSCardUIDlgSelectCardW(ocnwex)))
                    throw new Exception("SCardUIDlgSelectCardW");
            }
            catch (Exception e)
            {
                throw new InvalidOperationException("No se puede acceder a la Smart Card");
            }



            return result;
        }

        #endregion
    }
}
